/*
 "This product includes software developed by
 TouchGraph LLC (http://www.touchgraph.com/)."
 */

package abdn.graph.ontobrowser;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.net.URI;
import java.util.Enumeration;
import java.util.Vector;

import com.touchgraph.graphlayout.ClusterNode;
import com.touchgraph.graphlayout.Edge;
import com.touchgraph.graphlayout.TGPanel;

/**
 * OBNode: A LinkBrowser Node. Extends node by adding data storage for URL's,
     * hints. Some minor modifications have been made to the paint methods, allowing
 * node color to show through on selection, and adding horizontal lines for XML
 * nodes.
 *
 * @author Alexander Shapiro , Serguei Krivov
 *
 */

public class OBNode
    extends com.touchgraph.graphlayout.Node {

  // public final static int IS_UDEFINED = 0;
  // public final static int IS_OBJECT = 1;
  // public final static int IS_RELATION = 2;

  //   protected int category=IS_UDEFINED;
  public boolean hasArguments = false;

  public boolean isvariable = false;

  public static Font HINT_FONT = new Font("Courier", Font.PLAIN, 11);

  public static Color HINT_BACK_COLOR = Color.darkGray;

  public static Color HINT_TEXT_COLOR = Color.white;

  public static int MINIMUM_HINT_HEIGHT = 20;

  public String actionGroup;

  String url;

  URI uri;

  String name = null;

  public boolean hasLabel = false;

  boolean urlIsLocal = false;

  boolean urlIsXML = false;

  String hint;

  boolean hintIsHTML = false;

  int hintWidth = 300;

  int hintHeight = -1;

  //A value of less then MINIMUM_HINT_HEIGHT means that the hint height
  //is automatically determined
  Font hintFont;

  public int minCardinality = -1;

  public int maxCardinality = -1;

  private boolean inferred = false;

  private String namespace = "";

  public OBNode() {
    this(null, "", "");

  }

  public OBNode(String l) {
    this(null, l, "");
  }

  public OBNode(String id, String l, String u) {
    super(id, l);
    url = u;
    hint = "";
    hintFont = HINT_FONT;
  }

  public boolean isEdgeToThis(Edge n) {
    if (n.to == this) {
      return true;
    }
    else {
      return false;
    }

  }

  public boolean isEdgeFromThis(Edge n) {
    if (n.from == this) {
      return true;
    }
    else {
      return false;
    }
  }

  /*
   * public int getCategory() { return category; }
   *
   * public boolean isObjCategory() { if(category==1) return true; else return
   * false; }
   */

  public void setAsVariable(boolean var) {
    isvariable = var;
  }

  public boolean isVariable() {
    return isvariable;
  }

  public void setNodeHintFont(Font font) {
    HINT_FONT = font;
  }

  public void setNodeHintBackColor(Color color) {
    HINT_BACK_COLOR = color;
  }

  public void setNodeHintTextColor(Color color) {
    HINT_TEXT_COLOR = color;
  }

  public void setURL(String u) {
    url = u;
  }

  public String getURL() {
    return url;
  }

  public void setURI(URI u) {
    uri = u;

  }

  public URI getURI() {
    return uri;
  }

  public void setHint(String h) {
    hint = h;
  }

  public String getHint() {
    return hint;
  }

  public void setHintIsHTML(boolean hih) {
    hintIsHTML = hih;
  }

  public boolean getHintIsHTML() {
    return hintIsHTML;
  }

  public void setHintWidth(int hw) {
    hintWidth = hw;
  }

  public int getHintWidth() {
    return hintWidth;
  }

  public void setHintHeight(int hh) {
    hintHeight = hh;
  }

  public int getHintHeight() {
    return hintHeight;
  }

  public void setURLIsLocal(boolean uil) {
    urlIsLocal = uil;
  }

  public boolean getURLIsLocal() {
    return urlIsLocal;
  }

  public void setURLIsXML(boolean uix) {
    urlIsXML = uix;
  }

  public boolean getURLIsXML() {
    return urlIsXML;
  }

  public int getWidth() {
    if (fontMetrics != null && lbl != null) {
      if (typ != TYPE_ELLIPSE) {
        return fontMetrics.stringWidth(lbl) + 8;
      }
      else {
        return fontMetrics.stringWidth(lbl) + 28;
      }
    }
    else {
      return 8;
    }
  }

  public int getHeight() {
    if (fontMetrics != null) {
      return fontMetrics.getHeight() + 2;
    }
    else {
      return 8;
    }
  }

  Color myBrighter(Color c) {
    int r = c.getRed();
    int g = c.getGreen();
    int b = c.getBlue();

    if (b > r + 64 && b > g + 64) {
      r += 32;
      g += 32;
    }

    r = Math.min(r + 144, 255);
    g = Math.min(g + 144, 255);
    b = Math.min(b + 144, 255);

    return new Color(r, g, b);
  }

  public void paint(Graphics g, TGPanel tgPanel) {
    if (!intersects(tgPanel.getSize())) {
      return;
    }
    paintNodeBody(g, tgPanel);

    int ix = (int) drawx;
    int iy = (int) drawy;
    int h = getHeight();
    int w = getWidth();

    g.setColor(getPaintTextColor(tgPanel));
    if (urlIsXML) {
      g.drawLine(ix - w / 2 + 2, iy + h / 2 - 3, ix + w / 2 - 3, iy + h
                 / 2 - 3);
      g.drawLine(ix - w / 2 + 2, iy - h / 2 + 3, ix + w / 2 - 3, iy - h
                 / 2 + 3);
    }

    if (localEdgeNum() < edgeNum()) {
      int tagX = ix + (w - 6) / 2 - 2 + w % 2;
      int tagY = iy - h / 2 - 3;
      char character;
      int hiddenEdgeNum = edgeNum() - localEdgeNum();
      character = (hiddenEdgeNum < 9) ? (char) ('0' + hiddenEdgeNum)
          : '*';
      paintSmallTag(g, tgPanel, tagX, tagY, Color.red, Color.white,
                    character);
    }
  }

  public Color getPaintUnselectedBackColor() {
    if (fixed) {
      return BACK_FIXED_COLOR;
    }
    if (markedForRemoval) {
      return backColor.darker().darker();
    }
    if (justMadeLocal) {
      return myBrighter(backColor);
    }
    return backColor;
  }

  public Color getPaintTextColor(TGPanel tgPanel) {
    if (this == tgPanel.getSelect()) {
      return Color.BLACK; //getPaintUnselectedBackColor();
    }
    else {
      return textColor;
    }
  }

  public Color getPaintBackColor(TGPanel tgPanel) {
    if (this == tgPanel.getSelect()) {
      return BACK_SELECT_COLOR;
    }
    else {
      return getPaintUnselectedBackColor();
    }
  }

  public Color getPaintBorderColor(TGPanel tgPanel) {
    if (this == tgPanel.getSelect()) {
      if (fixed) {
        return BACK_FIXED_COLOR;
      }
      if (markedForRemoval) {
        return new Color(100, 60, 40);
      }
      if (justMadeLocal) {
        return new Color(255, 220, 200);
      }
      return borderColor; //return backColor;
    }
    else {
      return borderColor; //return super.getPaintBorderColor(tgPanel);
    }
  }

  public Vector getOutputs() {
    Vector out = new Vector();
    for (int i = 0; i < edges.size(); i++) {
      OBEdge edge = (OBEdge) edges.elementAt(i);
      if (isEdgeFromThis(edge)) {
        out.addElement(edge.to);
      }
    }
    return out;

  }

  public Vector getInputs() {
    Vector in = new Vector();
    for (int i = 0; i < edges.size(); i++) {
      OBEdge edge = (OBEdge) edges.elementAt(i);
      if (isEdgeToThis(edge)) {
        in.addElement(edge.from);
      }
    }
    return in;

  }

  public boolean hasOutput() {
    for (int i = 0; i < edges.size(); i++) {
      OBEdge edge = (OBEdge) edges.elementAt(i);
      if (isEdgeFromThis(edge)) {
        return true;
      }
    }
    return false;

  }

  public boolean hasInput() {
    for (int i = 0; i < edges.size(); i++) {
      OBEdge edge = (OBEdge) edges.elementAt(i);
      if (isEdgeToThis(edge)) {
        return true;
      }
    }
    return false;

  }

  public void deleteDependentNodes(TGPanel tgPanel) {
    Vector cledges = (Vector) edges.clone();

    for (Enumeration e = cledges.elements(); e.hasMoreElements(); ) {
      OBEdge edge = (OBEdge) e.nextElement();
      if (isEdgeFromThis(edge)) {
        if (edge.to instanceof OBRelationNode) {
          (edge.to).freeEdgesFromClusters();
          ClusterNode cn = (edge.to).getParentCluster();
          if (cn != null) {
            cn.removeNodeFromCluster(edge.to);
          }
          tgPanel.deleteNode(edge.to);
        }
      }
      else {
        if (edge.from instanceof OBRelationNode) {
          Vector outs = ( (OBRelationNode) edge.from).getOutputs();
          if (outs.size() < 2) {
            (edge.from).freeEdgesFromClusters();
            ClusterNode cn = (edge.from).getParentCluster();
            if (cn != null) {
              cn.removeNodeFromCluster(edge.from);
            }
            tgPanel.deleteNode(edge.from);
          }
        }
      }
    }
  }

  public boolean isEditable() {
    return namespace == null || namespace.length() == 0;
  }

  /**
   * @return
   */
  public String getNamespace() {
    return namespace;
  }

  /**
   * @param string
   */
  public void setNamespace(String string) {
    namespace = string;
  }

  /**
   * Method isInferred
   *
   * @return
   */
  public boolean isInferred() {
    return inferred;
  }

  /**
   * Method setInferred
   *
   * @param b
   */
  public void setInferred(boolean b) {
    inferred = b;
  }

  /**
   * @return Returns the name.
   */
  public String getName() {
    if (hasLabel) {
      return name;
    }
    else {
      return this.getLabel();
    }
  }

  /**
   * @param name
   *            The name to set.
   */
  public void setName(String name) {
    if (!hasLabel) {
      this.setLabel(name);
    }
    else {
      this.name = name;
    }
  }

  public String getNodeLabel() {
    if (hasLabel) {
      return this.getLabel();
    }
    else {
      return null;
    }
  }

  /**
   * @param name
   *            The name to set.
   */
  public void setNodeLabel(String lbl) {
    if (lbl == null) {
      hasLabel = false;
      if (name != null) {
        this.setLabel(this.name);
        this.name = null;
      }
      else {
        this.setLabel("");
      }
      return;
    }

    if (hasLabel) {
      this.setLabel(lbl);
    }
    else {
      this.name = this.getLabel();
      hasLabel = true;
      this.setLabel(lbl);
    }

  }
}
